﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace OpenXW
{
    public class Map
    {
        //CONSTANTS USED
        public const byte MAX_MAPX = 16;
        public const byte MAX_MAPY = 12;

        private string _Name;
        private int _Revision;
        private byte _Moral;

        private short _MapUp;
        private short _MapDown;
        private short _MapLeft;
        private short _MapRight;
        private short _Music;
        private short _BootMap;
        private short _ShopID;
        private byte _BootMapX;
        private byte _BootMapY;
        private byte _Weather;
        private bool Indoors = false;
        private bool Respawn = false;
        public Tile[,] _Tiles = new Tile[MAX_MAPX, MAX_MAPY];

        public String Name
        {
            get { return _Name; }
            set { _Name = value; }
        }



        public struct Tile
        {
            short _Ground;
            short _Mask;
            short _Animation;
            short _Mask2;
            short _Mask2Anim;
            short _Fringe;
            short _FringeAnim;
            short _Roof;
            short _Fringe2Anim;

            public TileType _Type;
            public TileType _Type_2;
            short _Data1;
            short _Data2;
            short _Data3;
            short _Data1_2;
            short _Data2_2;
            short _Data3_2;

            public short Data1_Layer1
            {
                get { return _Data1; }
                set { _Data1 = value; }
            }
            public short Data2_Layer1
            {
                get { return _Data2; }
                set { _Data2 = value; }
            }
            public short Data3_Layer1
            {
                get { return _Data3; }
                set { _Data3 = value; }
            }
            public short Data1_Layer2
            {
                get { return _Data1_2; }
                set { _Data1_2 = value; }
            }
            public short Data2_Layer2
            {
                get { return _Data2_2; }
                set { _Data2_2 = value; }
            }
            public short Data3_Layer2
            {
                get { return _Data3_2; }
                set { _Data3_2 = value; }
            }

            public short Ground
            {
                get { return _Ground; }
                set { _Ground = value; }
            }
            public short Mask
            {
                get { return _Mask; }
                set { _Mask = value; }
            }
            public short Animation
            {
                get { return _Animation; }
                set { _Animation = value; }
            }
            public short Mask2
            {
                get { return _Mask2; }
                set { _Mask2 = value; }
            }
            public short Mask2Anim
            {
                get { return _Mask2Anim; }
                set { _Mask2Anim = value; }
            }
            public short Fringe
            {
                get { return _Fringe; }
                set { _Fringe = value; }
            }
            public short FringeAnim
            {
                get { return _FringeAnim; }
                set { _FringeAnim = value; }
            }
            public short Roof
            {
                get { return _Roof; }
                set { _Roof = value; }
            }
            public short Fringe2Anim
            {
                get { return _Fringe2Anim; }
                set { _Fringe2Anim = value; }
            }

        }
        public enum TileType : byte
        {
            Block = 1,
            Direction_Block = 15,
            Door = 2,
            Warp = 10,
            Item = 3,
            Npc_Avoid = 4,
            Key = 5,
            Key_Open = 6,
            Heal = 8,
            Damage = 7,
            Sign = 11,
            Shop = 13,
            Npc = 12,
            No_Xing = 19,
            Walkthru = 20,
            Arena = 9,
            Roof = 21
        }

        public static Map FromFile(string fileName)
        {
            System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
            Map _Map = new Map();
            FileStream fs = new FileStream(@fileName, FileMode.Open);
            BinaryReader bReader = new BinaryReader(fs);

            //OFFSET 0: The first 20 bytes are the map name.
            _Map.Name = encoding.GetString(bReader.ReadBytes(20));

            //OFFSET 20: The revision is stored here @ 4 bytes.
            _Map._Revision = bReader.ReadInt32();

            //OFFSET 24: Contains the map moral as a byte.
            _Map._Moral = bReader.ReadByte();

            //OFFSET 25: Stored as 2 bytes, the map UP.
            _Map._MapUp = bReader.ReadInt16();

            //OFFSET 27: Stored as 2 bytes, the map DOWN.
            _Map._MapDown = bReader.ReadInt16();

            //OFFSET 29: Stored as 2 bytes, the map LEFT.
            _Map._MapLeft = bReader.ReadInt16();

            //OFFSET 31: Stored as 2 bytes, the map RIGHT.
            _Map._MapRight = bReader.ReadInt16();

            //OFFSET 33: Stored as 2 bytes, the map music.
            _Map._Music = bReader.ReadInt16();

            //OFFSET 35: Stored as 2 bytes, the Boot map.
            _Map._BootMap = bReader.ReadInt16();

            //OFFSET 37: Stored as a single byte, the boot X
            _Map._BootMapX = bReader.ReadByte();

            //OFFSET 38: Stored as a single byte, the boot Y
            _Map._BootMapY = bReader.ReadByte();

            //OFFSET 39: Stored as two bytes, the Shop ID.
            _Map._ShopID = bReader.ReadInt16();

            //OFFSET 41: Stored as a single byte, is the map indoors?
            if (bReader.ReadByte() == 1)
                _Map.Indoors = true;
            else
                _Map.Indoors = false;

            //Now, we decode the Tiles, a tile is 32 bytes in length
             long prevLength = bReader.BaseStream.Position;

             for (int y = 0; y < MAX_MAPY; y++)
            {
                for (int x = 0; x < MAX_MAPX; x++)
                {
                   
                    prevLength = bReader.BaseStream.Position;

                    _Map._Tiles[x, y].Ground = bReader.ReadInt16(); //42
                    _Map._Tiles[x, y].Mask = bReader.ReadInt16(); //44
                    _Map._Tiles[x, y].Animation = bReader.ReadInt16(); //46
                    _Map._Tiles[x, y].Fringe = bReader.ReadInt16(); //48                    
                    _Map._Tiles[x, y]._Type = (TileType)bReader.ReadByte(); //50
                    _Map._Tiles[x, y].Data1_Layer1 = bReader.ReadInt16(); //51
                    _Map._Tiles[x, y].Data2_Layer1 = bReader.ReadInt16(); //53
                    _Map._Tiles[x, y].Data3_Layer1 = bReader.ReadInt16(); //55
                    _Map._Tiles[x, y]._Type_2 = (TileType)bReader.ReadByte(); //57
                    _Map._Tiles[x, y].Data3_Layer2 = bReader.ReadInt16();
                    _Map._Tiles[x, y].Data3_Layer2 = bReader.ReadInt16();
                    _Map._Tiles[x, y].Data3_Layer2 = bReader.ReadInt16();
                    _Map._Tiles[x, y].Mask2 = bReader.ReadInt16(); //64
                    _Map._Tiles[x, y].Mask2Anim = bReader.ReadInt16();//66
                    _Map._Tiles[x, y].FringeAnim = bReader.ReadInt16(); //68
                    _Map._Tiles[x, y].Roof = bReader.ReadInt16();  //70
                    _Map._Tiles[x, y].Fringe2Anim = bReader.ReadInt16(); //72


                }
            }




            //DEBUG ONLY!!!
            bReader.BaseStream.Position = 6244;

            //OFFSET 6,244: Stored as a single byte, does the map respawn?
            if (bReader.ReadByte() == 1)
                _Map.Respawn = true;
            else
                _Map.Respawn = false;

            //OFFSET 6,245: Stored as a single byte, the weather.
            _Map._Weather = bReader.ReadByte();


            bReader.Close();
            return _Map;
        }


    }
}
